package cmm;

import spread.AdvancedMessageListener;
import spread.MembershipInfo;
import spread.SpreadException;
import spread.SpreadMessage;

public class AdvancedSpreadListener implements AdvancedMessageListener {

	private ClusterManagementModule CMM;
	
	private String LocalClusterMachineName;
	
	private MachineState LocalMachineState;
	
//  --------------------------------------------------------------------------------	
	
	public AdvancedSpreadListener(ClusterManagementModule CMM, String LocalClusterMachineName, MachineState localMachineState){
		this.CMM = CMM;
		this.LocalClusterMachineName = LocalClusterMachineName;
		LocalMachineState = localMachineState;
	}
	
	public void setLocalMachineState(MachineState localMachineState) {
		LocalMachineState = localMachineState;
	}
	
	public void membershipMessageReceived(SpreadMessage message) {

		// If this is a membership message
		if(message.isMembership()){
			MembershipInfo Info = message.getMembershipInfo();
			// If this message was caused by a "Join"
			if(Info.isCausedByJoin() & Info.isRegularMembership()){
				// The name of the joiner is as follows: #Connection-Name#Deamon-Name
				// Split the joiner name into it's parts
				String[] NameComps = Info.getJoined().toString().split("#");
				// Joiner name is the connection name - the 2nd String in the array.
				String JoinerName = NameComps[1];
				if(JoinerName.equals(LocalClusterMachineName)){
					// If this machine is the only one in the Cluster group
					if(Info.getMembers().length == 1){
						// Skip training
						CMM.ReceiveLocalFirstJoin();
					}
					else{
						// Execute training
						CMM.ReceiveLocalClusterJoin();
					}
				}
				else{
					// Add machine to mentoring list
					CMM.ReceiveNewMachineJoin(JoinerName); 
				}
			}
			else if(Info.isCausedByLeave() & Info.isRegularMembership()){
				// The name of the leaver is as follows: #Connection-Name#Deamon-Name
				// Split the leaver name into it's parts
				String[] NameComps = Info.getLeft().toString().split("#");
				// Leaver name is the connection name - the 2nd String in the array.
				String LeaverName = NameComps[1];
				// Report to the CMM
				CMM.ReceiveClusterLeave(LeaverName);
			}
		}
		
		// TEMP!!!
/*		if(message.isMembership()){
			MembershipInfo Info = message.getMembershipInfo();
			System.out.println("getJoined: " + Info.getJoined());
			System.out.println("getMembers: " + Info.getMembers());
			System.out.println("getGroup: " + Info.getGroup());
			
		}*/
	}

	public void regularMessageReceived(SpreadMessage message) {
		// TODO Write AdvancedSpreadListener.regularMessageReceived()

		try {
			// Get the cluster message from the spread message
			ClusterMessage ClusterMSG = (ClusterMessage)message.getObject();
			
			// Interpret the type of the message
			switch(ClusterMSG.getType()){
			// Application Messages
				case APP_NEW_TASK :
				{
					if(LocalMachineState == MachineState.TRAINING)
						CMM.StoreMessageWhileTraining(ClusterMSG);
					else if(LocalMachineState == MachineState.ACTIVE){
						// Convert the message to a "Application New Task" message object
						ClusterMessage_AppNewTask msg = (ClusterMessage_AppNewTask)ClusterMSG;
						// Inform the CMM of a "Application New Task" message
						CMM.ReceiveAppNewTask(msg.getSenderID(), msg.getTaskContext());
					}
					break;
				}
				case APP_UPDATE_TASK :
				{
					if(LocalMachineState == MachineState.TRAINING)
						CMM.StoreMessageWhileTraining(ClusterMSG);
					else if(LocalMachineState == MachineState.ACTIVE){
						// Convert the message to a "Application Update Task" message object
						ClusterMessage_AppUpdateTask msg = (ClusterMessage_AppUpdateTask)ClusterMSG;
						// Inform the CMM of an "Application Update Task" message
						CMM.ReceiveAppUpdateTask(msg.getSenderID(), msg.getTaskID(), msg.getContextUpdate());
					}
					break;
				}
				case APP_TERMINATE_TASK :
				{
					if(LocalMachineState == MachineState.TRAINING)
						CMM.StoreMessageWhileTraining(ClusterMSG);
					else if(LocalMachineState == MachineState.ACTIVE){
						// Convert the message to a "Application Terminate Task" message object
						ClusterMessage_AppTerminateTask msg = (ClusterMessage_AppTerminateTask)ClusterMSG;
						// Inform the CMM of an "Application Terminate Task" message
						CMM.ReceiveAppTerminateTask(msg.getSenderID(), msg.getTaskID());
					}
					break;
				}
			// Proxy Server Messages
				case PROXY_NEW_TASK :
				{
					if(LocalMachineState == MachineState.TRAINING)
						CMM.StoreMessageWhileTraining(ClusterMSG);
					else if(LocalMachineState == MachineState.ACTIVE){
						// Convert the message to a "Proxy New Task" message object
						ClusterMessage_ProxyNewTask msg = (ClusterMessage_ProxyNewTask)ClusterMSG;
						// Inform the CMM of a "Proxy New Task" message
						CMM.ReceiveProxyNewTask(msg.getSenderID(), msg.getProxyContext());
					}
					break;
				}
			// Training Messages
				case TRAINING_NEW_TASK :
				{
					if(LocalMachineState == MachineState.TRAINING)
						CMM.StoreMessageWhileTraining(ClusterMSG);
					else{
						// Convert the message into a "Training New Task" message object
						ClusterMessage_TrainingNewTask msg = (ClusterMessage_TrainingNewTask)ClusterMSG;
						// Inform the CMM of a "Training New Task" message
						CMM.ReceiveTrainingNewTask(msg.getSenderID(), msg.getData());
					}
					break;
				}
				case TRAINING_UPDATE_TASK :
				{
					// Convert the message into a "Training Update Task" message object
					ClusterMessage_TrainingUpdateTask msg = (ClusterMessage_TrainingUpdateTask)ClusterMSG;
					// Inform the CMM of a "Training Update Task" message
					CMM.ReceiveTrainingUpdateTask(msg.getSenderID(), msg.getTaskID(), msg.getData(), msg);
					break;
				}
				case TRAINING_TERMINATE_TASK :
				{
					// Convert the message into a "Training Update Task" message object
					ClusterMessage_TrainingTerminateTask msg = (ClusterMessage_TrainingTerminateTask)ClusterMSG;
					// Inform the CMM of a "Training Update Task" message
					CMM.ReceiveTrainingTerminateTask(msg.getSenderID(), msg.getTaskID(), msg.getTraineeName(), msg);
					break;
				}
			// Misc. Messages
				case NEW_SERVER_READY :
				{
					if(LocalMachineState == MachineState.TRAINING)
						CMM.StoreMessageWhileTraining(ClusterMSG);
					else{
						// Convert the message to a "New Server Ready" message object
						ClusterMessage_NewServerReady msg = (ClusterMessage_NewServerReady)ClusterMSG;
						// Inform the CMM of a "New Server Ready" message
						CMM.ReceiveNewServerReady(msg.getNewMachineEntry());
					}
					break;
				}
			// Unexpected Message
				default:
					// Inform the CMM that an unsupported message was recieved
					CMM.ReceiveUnsupportedMessage();
			}
			
		} catch (SpreadException e) {
			// TODO handle exception
			e.printStackTrace();
		}
	
	}

}
